#include "RadianAxisDrawer.h"
#include "RadianEditorMathHelper.h"
#include "RadianEditorController.h"
#include "RadianRenderWnd.h"

#include <QMouseEvent>
#include <QKeyEvent>
#include <QWheelEvent>
#include <QtGui>

#include "OgreManualObject.h"
#include "OgreCamera.h"
#include "OgreSceneManager.h"
#include "OgreSceneNode.h"
#include "OgreRay.h"
#include "OgreMeshManager.h"
#include "OgreEntity.h"

//--------------------------------------------------------------------------
const Ogre::Real RadianAxisDrawer::MouseSensitivity = 20.0f;
const Ogre::Real RadianAxisDrawer::AxisLength = 50.0f;
const Ogre::Real RadianAxisDrawer::AxisDleta = 10.0f;
const Ogre::Real RadianAxisDrawer::AxisWidth = 5.0f;
const Ogre::String RadianAxisDrawer::XY_PlaneMeshName = "XY_DummyPlane"; 
const Ogre::String RadianAxisDrawer::XZ_PlaneMeshName = "XZ_DummyPlane"; 
const Ogre::String RadianAxisDrawer::YZ_PlaneMeshName = "YZ_DummyPlane";
//--------------------------------------------------------------------------
RadianAxisDrawer::RadianAxisDrawer(RadianEditorController* parentController)
	:mParentController(parentController)
	,mXAxis(NULL)
	,mYAxis(NULL)
	,mZAxis(NULL)
	,mActiveMaterialName("axisVertexColour")
	,mInActiveMaterialName("axisVertexColour")
	,mEditMode(Edit_Move)
	,mAxisNode(NULL)
	,mIsXActive(false)
	,mIsYActive(false)
	,mIsZActive(false)
	,mVisible(false)
	,xy_dummyPlane(Math::Vector3::UNIT_X,0)
	,xz_dummyPlane(Math::Vector3::UNIT_Z,0)
	,yz_dummyPlane(Math::Vector3::UNIT_Y,0)
	,mPlane_xy(NULL)
	,mPlane_xz(NULL)
	,mPlane_yz(NULL)
	,mIsOnDragging(false)
{

}
//--------------------------------------------------------------------------
RadianAxisDrawer::~RadianAxisDrawer()
{
	if(mParentController)
	{
		mParentController->GetParentRenderWnd()->GetSceneMgr()->destroyManualObject(mXAxis);
		mParentController->GetParentRenderWnd()->GetSceneMgr()->destroyManualObject(mYAxis);
		mParentController->GetParentRenderWnd()->GetSceneMgr()->destroyManualObject(mZAxis);

		mParentController->GetParentRenderWnd()->GetSceneMgr()->destroySceneNode(mAxisNode);
		mAxisNode->detachAllObjects();
	}
}
//--------------------------------------------------------------------------
void RadianAxisDrawer::Update()
{
	if(mParentController->GetSelectedSceneNode())
	{
		QWidget* parentWidget = mParentController->GetParentWidget();
		Ogre::Camera* targetCamera = mParentController->GetParentRenderWnd()->GetCamera();
		Math::Vector3 cameraPos = targetCamera->getDerivedPosition();
		Ogre::Real distaceToCamera = mEditCenter.distance(cameraPos);
		Math::Vector3 axisScaleFacotr = distaceToCamera / 500.0f * Math::Vector3::UNIT_SCALE ; 

		mVisible = true;

		mAxisNode->setVisible(mVisible);
		mAxisNode->setScale(axisScaleFacotr);

		Ogre::SceneNode* selectedNode = mParentController->GetSelectedSceneNode();
		mEditCenter = selectedNode->_getDerivedPosition();
		mEditRotation = selectedNode->_getDerivedOrientation();
		mEditScale = selectedNode->_getDerivedScale();

		mAxisNode->_setDerivedPosition(mEditCenter);
		mAxisNode->_setDerivedOrientation(mEditRotation);

		UpdateAxisColors();

		return;

		//mXAxis->setMaterialName(0, mIsXActive? mActiveMaterialName: mInActiveMaterialName);
		//mYAxis->setMaterialName(0, mIsYActive? mActiveMaterialName: mInActiveMaterialName);
		//mZAxis->setMaterialName(0, mIsZActive? mActiveMaterialName: mInActiveMaterialName);

		
	}

	else if(mParentController->GetSelectedSceneNodes().size())
	{
		mVisible = true;
		return;
	}


	mAxisNode->setScale(Math::Vector3::UNIT_SCALE);
	mVisible = false;
	mAxisNode->setVisible(false);
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::MouseTest()
{
	if(!(mParentController->GetSelectedSceneNode()) && !(mParentController->GetSelectedSceneNodes().size()))
		return false;

	Update();

	QWidget* parentWidget = mParentController->GetParentWidget();
	Ogre::Camera* targetCamera = mParentController->GetParentRenderWnd()->GetCamera();
	Math::Vector3 cameraPos = targetCamera->getDerivedPosition();
	//Ogre::Real distaceToCamera = mEditCenter.distance(cameraPos);
	Ogre::Vector2 camera2D = RadianEditorMathHelper::WorldToScreen2D(cameraPos, targetCamera, parentWidget->width(),parentWidget->height());

	// the three axis edge to 2D.
	Ogre::Vector2 x2D = RadianEditorMathHelper::WorldToScreen2D(mEditCenter + mEditRotation * Math::Vector3(100, 0 ,0), targetCamera, parentWidget->width(),parentWidget->height());
	Ogre::Vector2 y2D = RadianEditorMathHelper::WorldToScreen2D(mEditCenter + mEditRotation * Math::Vector3(0, 100 ,0), targetCamera, parentWidget->width(),parentWidget->height());
	Ogre::Vector2 z2D = RadianEditorMathHelper::WorldToScreen2D(mEditCenter + mEditRotation * Math::Vector3(0, 0 ,100), targetCamera, parentWidget->width(),parentWidget->height());

	// 2d position of the axis center.
	Ogre::Vector2 center2D = RadianEditorMathHelper::WorldToScreen2D(mEditCenter, targetCamera, parentWidget->width(),parentWidget->height());

	// each distance from the mouse to the axis.

	float distanceToX = RadianEditorMathHelper::DistanceToLine(center2D.x, center2D.y
		,x2D.x,x2D.y
		,mMousePosition.x,mMousePosition.y);

	float distanceToY = RadianEditorMathHelper::DistanceToLine(center2D.x, center2D.y
		,y2D.x,y2D.y
		,mMousePosition.x,mMousePosition.y);


	float distanceToZ = RadianEditorMathHelper::DistanceToLine(center2D.x, center2D.y
		,z2D.x,z2D.y
		,mMousePosition.x,mMousePosition.y);

	mIsXActive = false;	
	mIsYActive = false;
	mIsZActive = false;

	if(distanceToX <= MouseSensitivity)
	{
		// yes, x axis got the first priority.
		mIsXActive = true;	
		mIsYActive = false;
		mIsZActive = false;

	}
	else if(distanceToY <= MouseSensitivity)
	{
		mIsXActive = false;	
		mIsYActive = true;
		mIsZActive = false;
	}

	else if(distanceToZ <= MouseSensitivity)
	{
		mIsXActive = false;	
		mIsYActive = false;
		mIsZActive = true;

	}
	return mIsXActive | mIsYActive | mIsZActive;
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::OnMouseMove(QMouseEvent* evt)
{
	QWidget* parentWidget = mParentController->GetParentWidget();
	Ogre::Vector2 mouseScreen(mMousePosition.x / parentWidget->width(), mMousePosition.y / parentWidget->height());

	Update();

	if(evt->buttons() & Qt::LeftButton)
	{
		if(mParentController->GetSelectedSceneNode())
		{
			Ogre::SceneNode* selectedNode = mParentController->GetSelectedSceneNode();

			switch(mEditMode)
			{
			case Edit_Move:
				Math::Vector3 moveDelta;
				if(mIsXActive && doMove(mouseScreen, Math::Vector3::UNIT_X, moveDelta))
				{
					selectedNode->translate(moveDelta.x, moveDelta.y, moveDelta.z, Ogre::Node::TS_WORLD);
					return true;
				}

				else if(mIsYActive && doMove(mouseScreen, Math::Vector3::UNIT_Y, moveDelta))
				{
					selectedNode->translate(moveDelta.x, moveDelta.y, moveDelta.z, Ogre::Node::TS_WORLD);
					return true;
				}

				else if(mIsZActive && doMove(mouseScreen, Math::Vector3::UNIT_Z, moveDelta))
				{
					selectedNode->translate(moveDelta.x, moveDelta.y, moveDelta.z, Ogre::Node::TS_WORLD);
					return true;
				}
				break;
			}
		}

		else if(mParentController->GetSelectedSceneNodes().size())
		{
			
		}	
	}

	else
	{
		MouseTest();
	}

	return false;
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::OnMouseUp(QMouseEvent* evt)
{
	if(evt->buttons() & Qt::LeftButton)
	{
		mIsOnDragging = false;
	}

	if(mParentController->GetSelectedSceneNode())
	{

	}

	else if(mParentController->GetSelectedSceneNodes().size())
	{

	}

	return false;
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::OnMouseDown(QMouseEvent* evt)
{
	if(evt->buttons() & Qt::LeftButton)
	{
		mIsOnDragging = MouseTest();
		return mIsOnDragging;
	}	

	return false;
}
//--------------------------------------------------------------------------
void RadianAxisDrawer::UpdateMousePosition(QPoint mousePos)
{
	mMousePosition = Ogre::Vector2(mousePos.x(), mousePos.y());
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::doMove(Ogre::Vector2 mousePos,Math::Vector3 dragNormal,Math::Vector3& moveDelta)
{
	Math::Vector3 posToCamera = mParentController->GetParentRenderWnd()->GetCamera()->getPosition() - mEditCenter;
	posToCamera.normalise();

	Math::Vector3 moveAxis = mEditRotation * dragNormal;
	Math::Vector3 planeK = moveAxis.crossProduct(posToCamera);
	planeK.normalise();

	planeK = planeK.crossProduct(moveAxis);
	planeK.normalise();

	Ogre::Plane dragPlane(planeK, mEditCenter);
	Ogre::Ray camRay = mParentController->GetParentRenderWnd()->GetCamera()->getCameraToViewportRay(mousePos.x, mousePos.y);
	std::pair<bool, Ogre::Real> result = camRay.intersects(dragPlane);

	if(!result.first)
		return false;


	Math::Vector3 targetPosition = camRay.getPoint(result.second);
	Math::Vector3 dragDelta = targetPosition - mEditCenter;
	moveDelta = dragDelta.dotProduct(moveAxis) * moveAxis;

	return true;
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::doRotate()
{
	return false;
}
//--------------------------------------------------------------------------
bool RadianAxisDrawer::doScale()
{
	return false;
}
//--------------------------------------------------------------------------
void RadianAxisDrawer::InitializeAxis()
{
	mAxisNode = mParentController->GetParentRenderWnd()->GetSceneMgr()->getRootSceneNode()->createChildSceneNode();
	
	mXAxis = mParentController->GetParentRenderWnd()->GetSceneMgr()->createManualObject();
	mYAxis = mParentController->GetParentRenderWnd()->GetSceneMgr()->createManualObject();
	mZAxis = mParentController->GetParentRenderWnd()->GetSceneMgr()->createManualObject();
	
	mXAxis->begin(mInActiveMaterialName,Ogre::RenderOperation::OT_LINE_STRIP);
	mXAxis->position(0, 0, 0);
	mXAxis->colour(Util::ColourValue::Red);
	mXAxis->position(AxisLength, 0, 0);
	mXAxis->colour(Util::ColourValue::Red);
	mXAxis->position(AxisLength - AxisDleta, 3, 0);
	mXAxis->colour(Util::ColourValue::Red);
	mXAxis->position(AxisLength - AxisDleta, -3, 0);
	mXAxis->colour(Util::ColourValue::Red);
	mXAxis->position(AxisLength, 0, 0);
	mXAxis->colour(Util::ColourValue::Red);
	mXAxis->end();

	mYAxis->begin(mInActiveMaterialName,Ogre::RenderOperation::OT_LINE_STRIP);
	mYAxis->position(0, 0, 0);
	mYAxis->colour(Util::ColourValue::Green);
	mYAxis->position(0, AxisLength, 0);
	mYAxis->colour(Util::ColourValue::Green);
	mYAxis->position(3, AxisLength - AxisDleta, 0);
	mYAxis->colour(Util::ColourValue::Green);
	mYAxis->position(-3, AxisLength - AxisDleta, 0);
	mYAxis->colour(Util::ColourValue::Green);
	mYAxis->position(0, AxisLength, 0);
	mYAxis->colour(Util::ColourValue::Green);
	mYAxis->end();

	mZAxis->begin(mInActiveMaterialName,Ogre::RenderOperation::OT_LINE_STRIP);
	mZAxis->position(0, 0, 0);
	mZAxis->colour(Util::ColourValue::Blue);
	mZAxis->position(0, 0, AxisLength);
	mZAxis->colour(Util::ColourValue::Blue);
	mZAxis->position(3, 0, AxisLength - AxisDleta);
	mZAxis->colour(Util::ColourValue::Blue);
	mZAxis->position(-3, 0, AxisLength - AxisDleta);
	mZAxis->colour(Util::ColourValue::Blue);
	mZAxis->position(0, 0, AxisLength);
	mZAxis->colour(Util::ColourValue::Blue);
	mZAxis->end();

	mXAxis->setRenderQueueGroup(100);
	mYAxis->setRenderQueueGroup(100);
	mZAxis->setRenderQueueGroup(100);


	mAxisNode->attachObject(mXAxis);
	mAxisNode->attachObject(mYAxis);
	mAxisNode->attachObject(mZAxis);


	if(!Ogre::MeshManager::getSingletonPtr()->resourceExists(XY_PlaneMeshName))
	{
		Ogre::MeshManager::getSingletonPtr()->createPlane(XY_PlaneMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, xy_dummyPlane, 30, 30, 1, 1, true, 1, 1, 1, Math::Vector3::UNIT_Z);
	}

	if(!Ogre::MeshManager::getSingletonPtr()->resourceExists(XZ_PlaneMeshName))
	{
		Ogre::MeshManager::getSingletonPtr()->createPlane(XZ_PlaneMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, xz_dummyPlane, 30, 30, 1, 1, true, 1, 1, 1, Math::Vector3::UNIT_Y);
	}

	if(!Ogre::MeshManager::getSingletonPtr()->resourceExists(YZ_PlaneMeshName))
	{
		Ogre::MeshManager::getSingletonPtr()->createPlane(YZ_PlaneMeshName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, yz_dummyPlane, 30, 30, 1, 1, true, 1, 1, 1, Math::Vector3::UNIT_X);
	}

	mPlane_xy = mParentController->GetParentRenderWnd()->GetSceneMgr()->createEntity(XY_PlaneMeshName);
	mPlane_xz = mParentController->GetParentRenderWnd()->GetSceneMgr()->createEntity(XZ_PlaneMeshName); 
	mPlane_yz = mParentController->GetParentRenderWnd()->GetSceneMgr()->createEntity(YZ_PlaneMeshName);
	
}
//--------------------------------------------------------------------------
void RadianAxisDrawer::UpdateAxisColors()
{
	Util::ColourValue activeColour(1, 1, 0 ,1);

	// x - axis.
	mXAxis->beginUpdate(0);
	mXAxis->position(0, 0, 0);
	mXAxis->colour(mIsXActive ? activeColour : Util::ColourValue::Red);
	mXAxis->position(AxisLength, 0, 0);
	mXAxis->colour(mIsXActive ? activeColour : Util::ColourValue::Red);
	mXAxis->position(AxisLength - AxisDleta, 3, 0);
	mXAxis->colour(mIsXActive ? activeColour : Util::ColourValue::Red);
	mXAxis->position(AxisLength - AxisDleta, -3, 0);
	mXAxis->colour(mIsXActive ? activeColour : Util::ColourValue::Red);
	mXAxis->position(AxisLength, 0, 0);
	mXAxis->colour(mIsXActive ? activeColour : Util::ColourValue::Red);
	mXAxis->end();

	// y - axis.
	mYAxis->beginUpdate(0);
	mYAxis->position(0, 0, 0);
	mYAxis->colour(mIsYActive ? activeColour : Util::ColourValue::Green);
	mYAxis->position(0, AxisLength, 0);
	mYAxis->colour(mIsYActive ? activeColour : Util::ColourValue::Green);
	mYAxis->position(3, AxisLength - AxisDleta, 0);
	mYAxis->colour(mIsYActive ? activeColour : Util::ColourValue::Green);
	mYAxis->position(-3, AxisLength - AxisDleta, 0);
	mYAxis->colour(mIsYActive ? activeColour : Util::ColourValue::Green);
	mYAxis->position(0, AxisLength, 0);
	mYAxis->colour(mIsYActive ? activeColour : Util::ColourValue::Green);
	mYAxis->end();

	// z - axis.
	mZAxis->beginUpdate(0);
	mZAxis->position(0, 0, 0);
	mZAxis->colour(mIsZActive ? activeColour : Util::ColourValue::Blue);
	mZAxis->position(0, 0, AxisLength);
	mZAxis->colour(mIsZActive ? activeColour : Util::ColourValue::Blue);
	mZAxis->position(3, 0, AxisLength - AxisDleta);
	mZAxis->colour(mIsZActive ? activeColour : Util::ColourValue::Blue);
	mZAxis->position(-3, 0, AxisLength - AxisDleta);
	mZAxis->colour(mIsZActive ? activeColour : Util::ColourValue::Blue);
	mZAxis->position(0, 0, AxisLength);
	mZAxis->colour(mIsZActive ? activeColour : Util::ColourValue::Blue);
	mZAxis->end();

}
//--------------------------------------------------------------------------